package easy.trace.agent;

import com.alibaba.ttl.TransmittableThreadLocal;
import easy.trace.Annotation;
import easy.trace.BinaryAnnotation;
import easy.trace.Endpoint;
import easy.trace.Span;
import easy.trace.agent.support.SampleImp;
import easy.trace.agent.support.TraceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Tracer {
    private static final Logger logger = LoggerFactory.getLogger(Tracer.class);
    private Sampler sampler;
    private static boolean isTraceStartedFail;
    private SyncTransfer transfer;
    private ThreadLocal<Span> spanThreadLocal;
    TraceService traceService;

    private Tracer() {
        this.sampler = new SampleImp();
        this.transfer = null;

        try {
            this.spanThreadLocal = new TransmittableThreadLocal();
        } catch (Exception var2) {
            var2.printStackTrace();
            this.spanThreadLocal = new ThreadLocal();
        }

    }

    public void removeParentSpan() {
        this.spanThreadLocal.remove();
    }

    public Span getParentSpan() {
        return (Span)this.spanThreadLocal.get();
    }

    public void setParentSpan(Span span) {
        this.spanThreadLocal.set(span);
    }

    public Span genSpan(Long traceId, Long pid, Long id, String spanName, String serviceId) {
        Span span = new Span();
        span.setId(id);
        span.setParentId(pid);
        span.setSpanName(spanName);
        span.setTraceId(traceId == null ? this.genTracerId() : traceId);
        span.setServiceId(serviceId);
        return span;
    }

    public Span genSpan(Long traceId, Long pid, Long id, String spanname, boolean isSample, String serviceId) {
        Span span = new Span();
        span.setId(id);
        span.setParentId(pid);
        span.setSpanName(spanname);
        span.setSample(isSample);
        span.setTraceId(traceId == null ? this.genTracerId() : traceId);
        span.setServiceId(serviceId);
        return span;
    }

    public Span newSpan(String serviceId, String spanName, Endpoint endpoint) {
        return this.newSpan(serviceId, spanName, endpoint, (Long)null);
    }

    public Span newSpan(String serviceId, String spanName) {
        return this.newSpan(serviceId, spanName, (Endpoint)null, (Long)null);
    }

    public Span newSpan(String serviceId, String spanName, Endpoint endpoint, Long traceId) {
        Span span = new Span();
        if (traceId != null) {
            span.setTraceId(traceId);
        } else {
            span.setTraceId(this.genTracerId());
        }

        span.setId(this.genSpanId());
        span.setSpanName(spanName);
        span.setServiceId(serviceId);
        return span;
    }

    public Endpoint newEndPoint() {
        return new Endpoint();
    }

    public Endpoint newEndPoint(String host, int port) {
        return new Endpoint(host, port);
    }

    public static Tracer getTracer() {
        return Tracer.TraceHolder.instance;
    }

    public void start() throws Exception {
        logger.info("-----tracer start-----" + this.transfer);
        this.transfer.start();
    }

    public static synchronized void startTraceWork() {
        try {
            getTracer().start();
        } catch (Exception var1) {
            logger.info("-----tracer start error-----");
            isTraceStartedFail = true;
            logger.error(var1.getMessage());
        }

    }

    public static boolean isTraceStartedFail() {
        return isTraceStartedFail;
    }

    public static void setTraceStartedFail(boolean isTraceStartedFail) {
        isTraceStartedFail = isTraceStartedFail;
    }

    public boolean isSample() {
        return this.sampler.isSample() && this.transfer != null && this.transfer.isReady();
    }

    public void addBinaryAnntation(BinaryAnnotation b) {
        Span span = (Span)this.spanThreadLocal.get();
        if (span != null) {
            span.addBinaryAnnotation(b);
        }

    }

    public void clientSendRecord(Span span, Endpoint endpoint, long start) {
        Annotation annotation = new Annotation();
        annotation.setValue("cs");
        annotation.setTimestamp(start);
        annotation.setHost(endpoint);
        span.addAnnotation(annotation);
    }

    public void clientReceiveRecord(Span span, Endpoint endpoint, long end) {
        Annotation annotation = new Annotation();
        annotation.setValue("cr");
        annotation.setHost(endpoint);
        annotation.setTimestamp(end);
        span.addAnnotation(annotation);
        this.transfer.syncSend(span);
    }

    public void serverReceiveRecord(Span span, Endpoint endpoint, long start) {
        Annotation annotation = new Annotation();
        annotation.setValue("sr");
        annotation.setHost(endpoint);
        annotation.setTimestamp(start);
        span.addAnnotation(annotation);
        this.spanThreadLocal.set(span);
    }

    public void serverSendRecord(Span span, Endpoint endpoint, long end) {
        Annotation annotation = new Annotation();
        annotation.setTimestamp(end);
        annotation.setHost(endpoint);
        annotation.setValue("ss");
        span.addAnnotation(annotation);
        this.transfer.syncSend(span);
    }

    public String getServiceId(String name) {
        String id = null;
        if (this.transfer != null) {
            id = this.transfer.getServiceId(name, Integer.valueOf(0));
        }

        return name;
    }

    public String getServiceId(String name, Integer type) {
        String id = null;
        if (this.transfer != null) {
            this.transfer.getServiceId(name, type);
        }

        return name;
    }

    public Long genTracerId() {
        return this.transfer == null ? 0L : this.transfer.getTraceId();
    }

    public Long genSpanId() {
        return this.transfer.getSpanId();
    }

    public void setTraceService(TraceService traceService) {
        this.traceService = traceService;
        logger.info("trace traceService started " + traceService.toString());
    }

    public void setTransfer(SyncTransfer transfer) {
        this.transfer = transfer;
        logger.info("trace transfer started " + transfer.toString());
    }

    private static class TraceHolder {
        static Tracer instance = new Tracer();

        private TraceHolder() {
        }
    }
}
